package org.liuwei.concucrent.base04;

/*ThreadPoolExecutor是可扩展的，通过查看源码可以发现，
 * 它提供了几个可以在子类化中改写的方法：
 beforeExecute,afterExecute,terminated.*/

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;

/**
 * 
 * @Title: TimingThreadPool03.java
 * @Package org.liuwei.concucrent.base04
 * @Description: TODO(扩展接口线程池)
 * @author 刘伟 15818570028@163.com
 * @date 2016年8月21日 下午10:08:25
 * @version V1.0
 */

/*
 * 在执行任务的线程中将调用beforeExecute和afterExecute等方法， 在这些方法中还可以添加日志、计时、监视或者统计信息收集的功能。
 * 无论任务是从run中正常返回，还是抛出一个异常而返回， afterExecute都会被调用。 如果任务在完成后带有一个Error，
 * 那么就不会调用afterExecute。如果beforeExecute抛出一个RuntimeException
 * ，那么任务将不被执行，并且afterExecute也不会被调用。
 * 在线程池完成关闭时调用terminated，也就是在所有任务都已经完成并且所有工作者线程也已经关闭后，
 * terminated可以用来释放Executor在其生命周期里分配的各种资源，此外还可以执行发送通知、 记录日志或者手动finalize统计等操作。
 * 下面就以给线程池添加统计信息为例（添加日志和及时等功能）：
 */
public class TimingThreadPool03 extends ThreadPoolExecutor {
	private final ThreadLocal<Long> startTime = new ThreadLocal<Long>();
	private final Logger log = Logger.getAnonymousLogger();
	private final AtomicLong numTasks = new AtomicLong();
	private final AtomicLong totalTime = new AtomicLong();

	public TimingThreadPool03(int corePoolSize, int maximumPoolSize,
			long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
	}

	protected void beforeExecute(Thread t, Runnable r) {
		super.beforeExecute(t, r);
		log.info(String.format("Thread %s: start %s", t, r));
		startTime.set(System.nanoTime());
	}

	protected void afterExecute(Runnable r, Throwable t) {
		try {
			long endTime = System.nanoTime();
			long taskTime = endTime - startTime.get();
			numTasks.incrementAndGet();
			totalTime.addAndGet(taskTime);
			log.info(String.format("Thread %s: end %s, time=%dns", t, r,
					taskTime));
		} finally {
			super.afterExecute(r, t);
		}
	}

	protected void terminated() {
		try {
			log.info(String.format("Terminated: avg time=%dns", totalTime.get()
					/ numTasks.get()));
		} finally {
			super.terminated();
		}
	}
}
